package org.mtmi.ui.controls;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Path;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.mtmi.ui.GraphicUtil;
import org.mtmi.ui.drawables.IDrawable;
import org.mtmi.ui.layouts.LayoutData;
import org.mtmi.ui.scenes.AnimationManager;
import org.mtmi.ui.scenes.CLR;
import org.mtmi.ui.scenes.COLOR;
import org.mtmi.ui.scenes.FontManager;
import org.mtmi.ui.scenes.IAnimated;
import org.mtmi.ui.scenes.Scene;

public class Button extends AbstractButton implements IAnimated
{
	private static final int hMargin = 20, vMargin = 14;
	
	private String text;
	private IDrawable image;
	private Point image_size;
	protected int animStep; //used to animate color for ToggleButton
	private Path outline;

	public Button(Scene scene, int flags ) {
		this( scene, null, flags );
	}
	
	public Button(Scene scene, String text, int flags ) {
		super( scene, flags );
		this.text = text;
		isEnabled = true;
	}

	public void setText(String text) {
		this.text = text;
		updateSize();
	}
	
	public void setImage( IDrawable img ) {
		image = img;
		updateSize();
	}
	
	public void setImageAndText( IDrawable img, String text ) {
		this.text = text;
		image = img;
		updateSize();
	}
	
	private void updateSize() {
		GC gc = new GC(Display.getDefault());
		try {
			LayoutData ld = new LayoutData( gc, 0,0,0,0 );
			setSize( computeSize( ld ) );
		} finally {
			gc.dispose();
		}
	}
	
	@Override
	public Point computeSize( LayoutData l ) {
		l.gc.setFont(FontManager.getInstance().getNormalFont());
		int w=0, h=0;
		if( text!=null ) {
			Point p = l.gc.stringExtent(text);
			w = p.x;
			h = p.y;
		}
		if( image!=null ) {
			image_size = image.computeSize( h, h ); //propose square from text height
			if( w>0 ) w+=hMargin;
			w += image_size.x;
			h = Math.max( h, image_size.y );
		}
		Point s = new Point( w+2*hMargin, h+2*vMargin );
		return s;
	}
	
	public String getText() { return text; }
	public IDrawable getImage() { return image; }
	
	@Override
	public void paint(GC gc) {
		gc.setAntialias(SWT.ON);
		gc.setTextAntialias(SWT.ON);
		gc.setFont(FontManager.getInstance().getNormalFont());
		gc.setLineWidth(borderWidth);
		
        //because there is no difference in paint for simple "down" state and checked one (up or down)
		boolean isDown = isTapped || isChecked;
		Color bga=null, fga=null;
		if(!isEnabled) {
			gc.setBackground( COLOR.grey20 );
			gc.setForeground( COLOR.grey60 );
			gc.setAlpha( 180 );
		} else {
			if( animStep==0 ) {
				if( isDown ) {
					gc.setBackground( COLOR.buttonTappedBg );
					gc.setForeground( COLOR.buttonTappedFg );
				} else {
					gc.setBackground( COLOR.sceneBg );
					gc.setForeground( COLOR.sceneFg );
				}
			}
			else {
				Color bgu = COLOR.sceneBg;
				Color fgu = COLOR.sceneFg;
				Color bgt = COLOR.buttonTappedBg;
				Color fgt = COLOR.buttonTappedFg;
				if( animStep<0 ) {//toggleButton goes to checked state
					float k = Math.abs(animStep)/100f;
					bga = CLR.mix( bgu, bgt, k );
					fga = CLR.mix( fgu, fgt, k );
					gc.setForeground( fgt );
				} else { // animStep>0 : toggleButton goes to unchecked state
					float k = animStep/100f;
					bga = CLR.mix( bgt, bgu, k );
					fga = CLR.mix( fgt, fgu, k );
					gc.setForeground( fgu );
				}
				gc.setBackground( bga );
				gc.setForeground( fga );
			}
		}
		outline = GraphicUtil.getRoundRectangle( gc, location.x+borderWidth/2, location.y+borderWidth/2, 
				size.x-borderWidth, size.y-borderWidth, (int)(size.y/3.0), (int)(size.y/3.0));
		gc.fillPath(outline);
		gc.drawPath(outline);
		boolean clip = text!=null || image!=null ;
		if( clip ) {
			//clip text, mandatory for reduced width buttons
			gc.setClipping( outline );
		}
		int x = location.x+hMargin;
		if( image != null ) {
			int y = location.y/*-borderWidth*/+(size.y-image_size.y)/2;
			int st = isEnabled ? ( isDown ? IDrawable.NORMAL : IDrawable.SELECTED) : IDrawable.DISABLED;
			image.paint( gc, x, y, image_size.x, image_size.y, st );
			x += hMargin + image_size.x;
		}
		if( text != null ) {
			Point s = gc.textExtent( text );
			int r = location.x+size.x-borderWidth/2;
			int xt = x + (r-x-s.x)/2-2*borderWidth;
			gc.drawText( text, xt, location.y/*-borderWidth*/+(size.y-s.y)/2, true );
		}
		if( clip ) {
			gc.setClipping( (Rectangle)null );
		}
		if( bga!=null ) bga.dispose();
		if( fga!=null ) fga.dispose();
		gc.setAlpha(255);
	}

	
	@Override
	public void setBounds( int x, int y, int w, int h ) {
		super.setBounds( x, y, w, h );
		//on Windows (XP ?), the following force a immediate redraw, which
		//failed into infinite loop when an animation calls setSize() (see MenuItemButton)
		//redraw();
	}

	@Override
	public boolean containsTouch(TouchControlEvent e) {
		return outline!=null && outline.contains( e.x, e.y, e.gc, false );
	}

	@Override
	public String toString() {
		return super.toString()+"{"+text+"}"; //$NON-NLS-1$ //$NON-NLS-2$
	}

	@Override
	public void setChecked(boolean checked) {
		super.setChecked(checked);
		redraw();
		startAnimation();
	}
	
	/** animate toggle button */
	private void startAnimation() {
		if( isToggleButton() && AnimationManager.getDefault().isAnimated() ) {
			if( animStep==0 ) {
				if( isChecked() ) {
					animStep = -10; //goes to checked
				} else {
					animStep = 10; //goes to unchecked
				}
				AnimationManager.getDefault().add( this );
			} else {
				//already in animation process, revert it:
				animStep=-animStep;
			}
		}
	}
	
	@Override
	public boolean animationStep() {
		if( animStep<=-100 ) {
			animStep=0;
		}
		else if( animStep >=100 ) {
			animStep = 0;
		}
		else if( animStep<0 ) {
			animStep-=20;
		}
		else if( animStep>0 ) {
			animStep+=20;
		}
		return animStep!=0;
	}
	
	@Override
	public boolean isAnimating() {
		return animStep!=0;
	}
}
